package plgbase

import (
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"strings"
	"time"
)

/*
**
1. status_o
2. output
*/
type InnerOutput struct {
	objdna      uint32
	plug        interface{}
	plugID      string
	topic       string // 状态数据发布
	interval    int
	intervalDNA int
	ownerPlug   interface{}
	templ       string // json 默认模版
	outTag      string
	ReleaseFlag int
}

func NewInnerOutput() *InnerOutput {
	return &InnerOutput{}
}

func (this *InnerOutput) Release() {
	this.ReleaseFlag = 1
	this.plug = nil
}

func (this *InnerOutput) SetPlug(val interface{}) {
	this.plug = val
	if val == nil {
		return
	}
}

func (this *InnerOutput) ConfigOwnerPlug(val interface{}) {
	this.ownerPlug = val
}

func (this *InnerOutput) createReportJSON() *wrapper.SuperValue {
	if len(this.templ) > 0 {
		json, _ := wrapper.NewSVFromBuf([]byte(this.GetTempl()))
		if json != nil {
			return json
		}
	}
	return wrapper.NewSVObject()
}

func (this *InnerOutput) CheckDNA() uint32 {
	if this.objdna == 0 {
		this.objdna = utils.NewObjectDNA()
	}
	return this.objdna
}

func (this *InnerOutput) OutputTopic() string {
	return this.topic
}

/*
*

	{
	    "id":"ex",
	    "topic":"xxxx",
	    "interval":1
	 }
*/
func (this *InnerOutput) ReloadConf(conf *wrapper.SuperValue,
	status_fn func(), status_fn_start func(), status_fn_shutdown func()) (err error) {

	if conf == nil {
		return
	}

	conf.CheckStrFunc("id", func(strv string) {
		this.plugID = strv
		ex := FindPluginByID(strv)
		this.SetPlug(ex)
	})

	conf.CheckStrFunc("topic", func(strv string) {
		this.topic = strv
	})

	conf.CheckStrFunc("tag", func(strv string) {
		this.outTag = strv
	})

	conf.CheckExistsStrFunc("templ", func(strv string) {
		this.templ = strv
	})

	conf.CheckExistsIntFunc("interval", func(val int64) {
		if this.interval != int(val) {
			this.intervalDNA++
			if this.interval <= 0 { // 之前关闭
				if status_fn_start != nil {
					status_fn_start()
				}
			}
			this.interval = int(val)
			if this.interval > 0 {
				dna := this.intervalDNA
				this.CheckDNA()
				utils.AddTaskFxiedInterval(fmt.Sprintf("obj_%d", this.objdna),
					time.Duration(this.interval)*time.Second, func() bool {
						if dna != this.intervalDNA || this.ReleaseFlag == 1 {
							if status_fn_shutdown != nil {
								status_fn_shutdown()
							}
							return false
						}
						if status_fn != nil {
							status_fn()
						}
						return true
					})
			} else {
				if status_fn_shutdown != nil {
					status_fn_shutdown()
				}
			}

		}

	})
	return
}

func (this *InnerOutput) checkGetPlug() interface{} {
	ex := this.plug
	if ex == nil {
		ex = FindPluginByID(this.plugID)
		if ex != nil {
			this.plug = ex
		}
	}
	return ex
}

func (this *InnerOutput) OutputBufferTag(buffer []byte, tag interface{}) {
	if this.ReleaseFlag == 1 {
		return
	}

	ex := this.checkGetPlug()
	if ex == nil {
		return
	}

	if sc, ok := ex.(IGetSubscriber); ok {
		sc.GetSubscriber().DispatchData(this.topic, this, buffer, tag)
	} else if sc, ok := ex.(utils.SubscribeCenter); ok {
		sc.DispatchData(this.topic, this, buffer, tag)
	} else if sc, ok := ex.(ISendKVs); ok {
		sc.SendKVs(this.topic, buffer)
	}
}

func (this *InnerOutput) OutputBufferEx(buffer []byte, sender interface{}, tag interface{}) {
	if this.ReleaseFlag == 1 {
		return
	}

	ex := this.checkGetPlug()
	if ex == nil {
		return
	}

	if sc, ok := ex.(IGetSubscriber); ok {
		sc.GetSubscriber().DispatchData(this.topic, sender, buffer, tag)
	} else if sc, ok := ex.(utils.SubscribeCenter); ok {
		sc.DispatchData(this.topic, sender, buffer, tag)
	} else if sc, ok := ex.(ISendKVs); ok {
		sc.SendKVs(this.topic, buffer)
	}
}

func (this *InnerOutput) OutputData(topic string, data interface{}, sender interface{}, tag interface{}) {
	if this.ReleaseFlag == 1 {
		return
	}

	ex := this.checkGetPlug()
	if ex == nil {
		return
	}

	if len(topic) == 0 {
		topic = this.topic
	}

	if tag == nil {
		tag = this.outTag
	}

	if sc, ok := ex.(IDispatchData); ok {
		sc.DispatchData(topic, sender, data, tag)
	} else if sc, ok := ex.(IGetSubscriber); ok {
		sc.GetSubscriber().DispatchData(topic, sender, data, tag)
	} else if sc, ok := ex.(utils.SubscribeCenter); ok {
		sc.DispatchData(topic, sender, data, tag)
	} else if sc, ok := ex.(ISendKVs); ok {
		sc.SendKVs(topic, data)
	}
}

func (this *InnerOutput) OutputBuffer(buffer []byte) {
	if this.ReleaseFlag == 1 {
		return
	}

	ex := this.checkGetPlug()
	if ex == nil {
		return
	}

	if sc, ok := ex.(IDispatchData); ok {
		sc.DispatchData(this.topic, this, buffer, nil)
	} else if sc, ok := ex.(IGetSubscriber); ok {
		sc.GetSubscriber().DispatchData(this.topic, this, buffer, nil)
	} else if sc, ok := ex.(utils.SubscribeCenter); ok {
		sc.DispatchData(this.topic, this, buffer, nil)
	} else if sc, ok := ex.(ISendKVs); ok {
		sc.SendKVs(this.topic, buffer)
	}
}

func (this *InnerOutput) SendStatus(msg string) {
	if this.ReleaseFlag == 1 {
		return
	}

	ex := this.checkGetPlug()
	if ex == nil {
		return
	}
	if sc, ok := ex.(IDispatchData); ok {
		sc.DispatchData(this.topic, this, msg, nil)
	} else if sc, ok := ex.(IGetSubscriber); ok {
		sc.GetSubscriber().DispatchData(this.topic, this, msg, nil)
	} else if sc, ok := ex.(utils.SubscribeCenter); ok {
		sc.DispatchData(this.topic, this, msg, nil)
	} else if sc, ok := ex.(ISendKVs); ok {
		sc.SendKVs(this.topic, msg)
	}
}

func (this *InnerOutput) SendStatusFunc(fillStatus func(json *wrapper.SuperValue)) {
	if this.ReleaseFlag == 1 {
		return
	}

	this.SendStatusFuncEx(func(json *wrapper.SuperValue) bool {
		fillStatus(json)
		return true
	})
}

func (this *InnerOutput) SendStatusFuncEx(fillStatus func(json *wrapper.SuperValue) bool) {
	if this.ReleaseFlag == 1 {
		return
	}

	this.SendJsonFunc(this.topic, fillStatus)
}

func (this *InnerOutput) GetTempl() string {
	rval := ReplacePlaceholderForFileName(this.templ)
	rval = strings.ReplaceAll(rval, "$plugid$", GetPlugID(this.ownerPlug, ""))
	rval = strings.ReplaceAll(rval, "$now$", utils.NowString())

	return rval
}

func (this *InnerOutput) SendJsonFunc(topic string, fillStatus func(json *wrapper.SuperValue) bool) {
	if this.ReleaseFlag == 1 {
		return
	}

	ex := this.checkGetPlug()
	if ex == nil {
		return
	}
	if sc, ok := ex.(IDispatchData); ok {
		json := this.createReportJSON()
		if !fillStatus(json) {
			return
		}
		sc.DispatchData(topic, this, json, nil)
	} else if sc, ok := ex.(IGetSubscriber); ok {
		json := this.createReportJSON()
		if !fillStatus(json) {
			return
		}
		sc.GetSubscriber().DispatchData(this.topic, this, json, nil)
	} else if sc, ok := ex.(utils.SubscribeCenter); ok {
		json := this.createReportJSON()
		if !fillStatus(json) {
			return
		}
		sc.DispatchData(topic, this, json, nil)
	} else if sc, ok := ex.(ISendKVs); ok {
		json := this.createReportJSON()
		if !fillStatus(json) {
			return
		}
		sc.SendKVs(topic, json)
	}
}
